﻿Public Class PlaylistReader

#Region " AVPL "
  Public Shared Function ParseAVPLFile(ByVal avpl As String) As AVPLPlaylist
    Try
      Dim ap As New AVPLPlaylist
      ap.LoadFromFile(avpl)
      Return ap
    Catch
      Return Nothing
    End Try
  End Function
#End Region

#Region " PLS "
  Public Shared Function ParsePLSString(ByVal pls As String) As StandardPlaylist
    Dim ini As New AvianWaves.Ini.File
    ini.LoadData(pls)
    Return ParsePLS_Worker(ini)
  End Function

  Public Shared Function ParsePLSFile(ByVal pls As System.IO.Stream) As StandardPlaylist
    Dim ini As New AvianWaves.Ini.File
    ini.LoadData(pls)
    Return ParsePLS_Worker(ini)
  End Function

  Public Shared Function ParsePLSFile(ByVal file As String) As StandardPlaylist
    Dim strm As IO.FileStream = Nothing
    Try
      strm = New IO.FileStream(file, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
      Return ParsePLSFile(strm)
    Catch ex As Exception
      Return New StandardPlaylist ' Calling class should verify that file exists... this is just a fail safe
    Finally
      If strm IsNot Nothing Then
        Try : strm.Close() : Catch : End Try
      End If
    End Try
  End Function

  Private Shared Function ParsePLS_Worker(ByVal ini As Ini.File) As StandardPlaylist
    Dim pl As New StandardPlaylist

    Try
      Dim num As Integer = Integer.Parse(ini.SectionNoNull("playlist").IntegerValueNoNull("NumberOfEntries"))

      For i As Integer = 1 To num
        Dim ple As New StandardPlaylistEntry
        ple.Location = ini.SectionNoNull("playlist").StringValueNoNull("File" & i)
        ple.Title = ini.SectionNoNull("playlist").StringValueNoNull("Title" & i)

        Try
          ple.Length = Integer.Parse(ini.SectionNoNull("playlist").IntegerValueNoNull("Length" & i))
        Catch
          ple.Length = -1
        End Try

        pl.Entries.Add(ple)
      Next

    Catch ex As Exception
      pl.ErrorsOnLoad = True
    End Try

    Return pl
  End Function
#End Region

#Region " M3U / M3U8 "
  Public Shared Function ParseM3UString(ByVal m3u As String) As StandardPlaylist
    Dim useEXTINF As Boolean = False
    Dim length As Integer = -1
    Dim title As String = ""

    ' Clean up all the newlines for parsing
    m3u = m3u.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr)

    ' Initialize the playlist
    ParseM3UString = New StandardPlaylist

    ' Parse each line
    For Each line As String In m3u.Split(vbCr)
      ' Eat whitespace
      line = line.Trim

      ' Look for directive character
      If line.Trim.Length > 0 Then
        If line(0) = "#"c Then
          ' This is a directive.  For friendly parsing purposes, we'll ignore everything except EXTINF instead of being mega-strict
          If line.Length > 8 AndAlso Left(line, 8).ToUpper = "#EXTINF:" Then
            ' Go past directive
            line = Mid(line, 9)

            ' Indicate we have an EXTINF directive
            useEXTINF = True

            ' Find index the length and title portions
            Dim idx As Integer = line.IndexOf(","c)
            If idx >= 0 Then
              Try
                length = Integer.Parse(Left(line, idx).Trim)
              Catch
                length = -1
              End Try
              title = Mid(line, idx + 2).Trim
            Else
              title = line.Trim
              length = -1
            End If
          End If
        Else
          If useEXTINF Then
            ' Create new entry using EXTINF data from previous valid line
            Dim entry As New StandardPlaylistEntry
            useEXTINF = False
            entry.Title = title
            entry.Length = length
            entry.Location = line.Trim
            ParseM3UString.Entries.Add(entry)
          Else
            ' Is the location a file or folder?
            Dim di As New System.IO.DirectoryInfo(line.Trim)
            If di.Exists Then
              ' This is a whole folder!  We need to add every file (non-media files should be filtered by the player itself, not here since we have no knowledge what is a valid media file right now)
              For Each fi As IO.FileInfo In di.GetFiles
                ParseM3UString.Entries.Add(ParseM3U_GetInfoFromString(fi.FullName))
              Next
            Else
              ' This is a single file
              ParseM3UString.Entries.Add(ParseM3U_GetInfoFromString(line.Trim))
            End If
          End If
        End If
      End If
    Next
  End Function

  Private Shared Function ParseM3U_GetInfoFromString(ByVal Str As String) As StandardPlaylistEntry
    ParseM3U_GetInfoFromString = New StandardPlaylistEntry
    ParseM3U_GetInfoFromString.Location = Str

    If Str.Contains("\") Then
      ParseM3U_GetInfoFromString.Title = Mid(Str, Str.IndexOf("\") + 2).Trim
      If ParseM3U_GetInfoFromString.Title = "" Then
        ParseM3U_GetInfoFromString.Title = Str
      End If
    Else
      ParseM3U_GetInfoFromString.Title = Str
    End If
  End Function


  Public Shared Function ParseM3UFile(ByVal m3u As System.IO.Stream) As StandardPlaylist
    Dim f As New IO.StreamReader(m3u, True) ' Automatically detects ASCII versus UTF-8, so no need to manually specificy M3U or M3U8
    Try
      Return ParseM3UString(f.ReadToEnd)
    Finally
      Try : f.Close() : Finally : End Try
    End Try
  End Function

  Public Shared Function ParseM3UFile(ByVal file As String) As StandardPlaylist
    Dim strm As IO.FileStream = Nothing
    Try
      strm = New IO.FileStream(file, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
      Return ParseM3UFile(strm)
    Catch ex As Exception
      Return New StandardPlaylist ' Calling class should verify that file exists... this is just a fail safe
    Finally
      If strm IsNot Nothing Then
        Try : strm.Close() : Catch : End Try
      End If
    End Try
  End Function

#End Region

End Class

